package main

import (
	"fmt"
	"gitee.com/kinwyb/appTools/appTool"
	"gitee.com/kinwyb/appTools/manager"
	"gitee.com/kinwyb/conv"
	"github.com/emicklei/go-restful"
	restfulspec "github.com/kinwyb/go-restful-openapi"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const swaggerApiTag = "Api"
const swaggerAgentTag = "Agent"

func initHttp(http *appTool.RestfulHttp) {
	apiWS := &restful.WebService{}
	apiWS.Produces(restful.MIME_JSON, restful.MIME_XML)
	apiWS.Path("/v1").Doc("服务端API")
	apiRoute(apiWS)
	apiWS.Route(agentPprofApi(apiWS.GET("/pprof").Doc("agent pprof")))
	http.AddService(apiWS)

	agentWS := &restful.WebService{}
	agentWS.Produces(restful.MIME_JSON, restful.MIME_XML)
	agentWS.Path("/v1/agent").Doc("客户端API")
	agentRoute(agentWS)
	http.AddService(agentWS)
}

func apiRoute(ws *restful.WebService) {
	ws.Route(downFileApi(ws.GET("/file/down").Doc("文件下载")))
	ws.Route(agentsApi(ws.GET("/agents").Doc("agent信息")))
	ws.Route(allAgentsApi(ws.GET("/agents/all").Doc("获取所有agent信息")))
	ws.Route(versionApi(ws.GET("/version").Doc("运行版本信息")))
	ws.Route(execsApi(ws.GET("/execs").Doc("运行软件名称")))
	ws.Route(allTcpConnApi(ws.GET("/conns").Doc("获取所有链接对象")))
}

// 文件下载
func downFileApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerApiTag).
		Param(restful.QueryParameter("file", "文件名").Required(true).DataType("string")).
		Param(restful.QueryParameter("version", "版本号").Required(true).DataType("string")).
		Param(restful.QueryParameter("os", "操作系统").Required(true).DataType("string")).
		To(func(request *restful.Request, response *restful.Response) {
			filename := request.QueryParameter("file")
			if filename == "" {
				response.WriteHeader(500)
				response.Header().Add("error", "下载文件名不能为空")
				return
			}
			osName := request.QueryParameter("os")
			if osName == "" {
				response.WriteHeader(500)
				response.Header().Add("error", "操作系统不能为空")
				return
			}
			ver := request.QueryParameter("version")
			if ver == "" {
				ver = "0.0.0"
			}
			manager.ServiceLog.Infof("下载执行文件[%s]:[%s] => ", filename, ver)
			execMapMutex.RLock()
			execFiles := execMap[filename]
			execMapMutex.RUnlock()
			execFile := ""
			for _, v := range execFiles {
				if v.os == osName && v.version == ver {
					execFile = v.fileName
					break
				}
			}
			if execFile == "" {
				response.WriteHeader(500)
				response.Header().Add("error", "文件信息不存在")
				return
			}
			execFilePath := filepath.Join(defaultAppDir, execFile)
			manager.ServiceLog.Infof("下载执行文件路径:%s", execFilePath)
			info, e := os.Stat(execFilePath)
			if os.IsNotExist(e) {
				response.WriteHeader(500)
				response.Header().Add("error", "文件不存在")
				return
			}
			response.ResponseWriter.Header().Set("Content-Length", fmt.Sprintf("%d", info.Size()))
			http.ServeFile(response.ResponseWriter, request.Request, execFilePath)
		}).Returns(http.StatusOK, "文件", []byte(""))
}

// agent信息
func agentsApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerApiTag).
		Param(restful.QueryParameter("app", "应用名").Required(true).DataType("string")).
		Param(restful.QueryParameter("os", "操作系统").Required(true).DataType("string")).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			var ret []agentInfo
			osName := request.QueryParameter("os")
			if osName == "" {
				resp.ParamMissing("os")
				return
			}
			appName := request.QueryParameter("app")
			if appName == "" {
				resp.ParamMissing("app")
				return
			}
			execMapMutex.RLock()
			for _, v := range agentClients {
				if v.OS == osName && v.AppName == appName {
					data := *v
					data.ID = strings.TrimPrefix(data.ID, v.AppName+"-")
					if data.IsStart && data.RunTime != "" {
						startTime := conv.ToInt64(data.RunTime)
						if startTime > 0 {
							runTime := time.Now().Unix() - startTime
							hourTime := runTime % 86400
							dayTime := (runTime - hourTime) / 86400
							miuTime := hourTime % 3600
							hourTime = (hourTime - miuTime) / 3600
							secTime := miuTime % 60
							miuTime = (miuTime - secTime) / 60
							data.RunTime = fmt.Sprintf("%d天 %d小时 %d分钟 %d秒", dayTime, hourTime, miuTime, secTime)
						}
					}
					ret = append(ret, data)
				}
			}
			execMapMutex.RUnlock()
			sort.Sort(agentInfoSlice(ret))
			resp.Succ(ret)
		}).Returns(http.StatusOK, "应用信息", []agentInfo{})
}

// 所有agent信息
func allAgentsApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerApiTag).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			var ret []agentInfo
			agentClientMutex.RLock()
			for _, v := range agentClients {
				agent := *v
				if agent.IsStart && agent.RunTime != "" {
					startTime := conv.ToInt64(agent.RunTime)
					if startTime > 0 {
						runTime := time.Now().Unix() - startTime
						hourTime := runTime % 86400
						dayTime := (runTime - hourTime) / 86400
						miuTime := hourTime % 3600
						hourTime = (hourTime - miuTime) / 3600
						secTime := miuTime % 60
						miuTime = (miuTime - secTime) / 60
						agent.RunTime = fmt.Sprintf("%d天 %d小时 %d分钟 %d秒", dayTime, hourTime, miuTime, secTime)
					}
				}
				ret = append(ret, agent)
			}
			agentClientMutex.RUnlock()
			resp.Succ(ret)
		}).Returns(http.StatusOK, "应用信息", []agentInfo{})
}

// 版本信息
func versionApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerApiTag).
		Param(restful.QueryParameter("exec", "程序名").Required(true).DataType("string")).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			exec := request.QueryParameter("exec")
			if exec == "" {
				resp.ParamMissing("exec")
				return
			}
			osv := strings.Split(exec, "_")
			execMapMutex.RLock()
			execFiles := execMap[osv[0]]
			execMapMutex.RUnlock()
			if len(execFiles) < 1 {
				resp.ErrorMsg("运行程序不存在")
				return
			}
			showAll := len(osv) < 2
			if showAll {
				var linux, windows, macos string
				for _, v := range execFiles {
					switch strings.ToLower(v.os) {
					case "linux":
						linux = v.version
					case "windows":
						windows = v.version
					case "darwin":
						macos = v.version
					}
				}
				resp.Succ(fmt.Sprintf("%s|%s|%s", linux, macos, windows))
				return
			} else {
				for _, v := range execFiles {
					if strings.ToLower(v.os) == osv[1] {
						resp.Succ(v.version)
						return
					}
				}
				resp.ErrorMsg("运行程序不存在")
				return
			}
		}).Returns(http.StatusOK, "运行版本", "")
}

// 获取运行软件名称
func execsApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerApiTag).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			var ret []string
			execMapMutex.RLock()
			for k := range execMap {
				ret = append(ret, k)
			}
			execMapMutex.RUnlock()
			sort.Strings(ret)
			resp.Succ(ret)
		}).Returns(http.StatusOK, "运行软件名称", []string{})
}

// 所有tcp信息
func allTcpConnApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerApiTag).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			if tcpServer != nil {
				var ret = tcpServer.GetAllConnIDs()
				resp.Succ(ret)
			} else {
				resp.ErrorMsg("服务端尚未初始化")
			}
		}).Returns(http.StatusOK, "tcp链接信息", []string{})
}

// 获取agent的pprof内容
func agentPprofApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerApiTag).
		Param(restful.QueryParameter("agent", "agent").Required(true).DataType("string")).
		Param(restful.QueryParameter("path", "pprof地址").Required(true).DataType("string")).
		Param(restful.QueryParameter("debug", "是否debug").DataType("string")).
		To(func(request *restful.Request, response *restful.Response) {
			path := request.QueryParameter("path")
			if path == "" {
				resp := appTool.RestfulRequest(request, response)
				resp.ErrorMsg("path不能为空")
				return
			}
			debugV := request.QueryParameter("debug")
			if conv.ToBoolDefault(debugV, false) {
				debugV = "?debug=1"
			} else {
				debugV = ""
			}
			agentID := request.QueryParameter("agent")
			if agentID == "" {
				resp := appTool.RestfulRequest(request, response)
				resp.ErrorMsg("agent不能为空")
				return
			}
			agentClientMutex.Lock()
			agent := agentClients[agentID]
			agentClientMutex.Unlock()
			if agent == nil {
				resp := appTool.RestfulRequest(request, response)
				resp.ErrorMsg("agent不存在")
				return
			}
			req := manager.CmdHttpRequest{
				Url:     "http://127.0.0.1" + path + debugV,
				Method:  http.MethodGet,
				Body:    nil,
				Headers: nil,
			}
			body, err := clientHttpRequest(agent.Client, req)
			if err != nil {
				response.Write([]byte(err.Error()))
			} else {
				response.Write(body)
			}
		}).Returns(http.StatusOK, "获取agent的pprof内容", []string{})
}

func agentRoute(ws *restful.WebService) {
	ws.Filter(agentFilter)
	ws.Route(stopProcessApi(ws.POST("/process/stop").Doc("停止一个进程")))
	ws.Route(startProcessApi(ws.POST("/process/start").Doc("开启一个进程")))
	ws.Route(stateProcessApi(ws.GET("/process/state").Doc("运行状态")))
	ws.Route(updateProcessApi(ws.POST("/process/update/exec").Doc("更新进运行程序版本")))
}

func agentFilter(request *restful.Request, response *restful.Response, chain *restful.FilterChain) {
	agentID := request.HeaderParameter("agent")
	if agentID == "" {
		resp := appTool.RestfulRequest(request, response)
		resp.ErrorMsg("agent不能为空")
		return
	}
	agentClientMutex.Lock()
	agent := agentClients[agentID]
	agentClientMutex.Unlock()
	if agent == nil {
		resp := appTool.RestfulRequest(request, response)
		resp.ErrorMsg("agent不存在")
		return
	}
	request.SetAttribute("agent", agent)
	chain.ProcessFilter(request, response)
}

// 获取请求的上下文对象
func getAgent(request *restful.Request) *agentInfo {
	val := request.Attribute("agent")
	if val == nil {
		return nil
	}
	if agent, ok := val.(*agentInfo); ok {
		return agent
	}
	return nil
}

// 停止进程
func stopProcessApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerAgentTag).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			agent := getAgent(request)
			if agent == nil {
				return
			}
			res, err := stopProcess(agent.Client, true)
			if res {
				resp.Succ("进程停止成功")
			} else {
				resp.Error(err)
			}
		}).Returns(http.StatusOK, "执行结果", "")
}

// 启动进程
func startProcessApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerAgentTag).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			agent := getAgent(request)
			if agent == nil {
				return
			}
			res, err := startProcess(agent.Client, true)
			if res {
				resp.Succ("进程启动成功")
			} else {
				resp.Error(err)
			}
		}).Returns(http.StatusOK, "执行结果", "")
}

// 进程状态
func stateProcessApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerAgentTag).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			agent := getAgent(request)
			if agent == nil {
				return
			}
			getProcessStatus(agent.Client)
			resp.Succ(agent.IsStart)
		}).Returns(http.StatusOK, "执行结果", "")
}

// 更新运行程序
func updateProcessApi(rb *restful.RouteBuilder) *restful.RouteBuilder {
	return rb.Metadata(restfulspec.KeyOpenAPITags, swaggerAgentTag).
		To(func(request *restful.Request, response *restful.Response) {
			resp := appTool.RestfulRequest(request, response)
			agent := getAgent(request)
			if agent == nil {
				return
			}
			res, err := updateProcess(agent.Client)
			if res {
				resp.Succ("程序版本已更新")
			} else {
				resp.Error(err)
			}
		}).Returns(http.StatusOK, "执行结果", "")
}
